home *** CD-ROM | disk | FTP | other *** search
- ;; Funktionen zur Bestimmung der asymptotischen Entwicklung von Folgen
- ;; Hartmut Maennel, Bruno Haible
- ;; August 1989
- ;; Version für Long-Floats 30.8.1989
-
- (provide 'folgen-asymptotik)
-
- ; Interpoliert eine Funktion an einer Wertemenge durch ein Polynom:
- ; yfun(t) = sum(j>=0, c[j]*(xfun(t)-x0)^j) .
- ; stellen ist eine Sequence, die die Auswertungsstellen enthält.
- ; Wert ist ein Array der Koeffizienten #(c[0] c[1] ...)
- ; bei Entwicklung des Polynoms um die Stelle x0.
- (defun polynom-interpol (xfun yfun stellen &optional (x0 0))
- (let* ((len (length stellen))
- (xwerte (map 'array xfun stellen))
- (ywerte (map 'array yfun stellen)))
- ; Nun ist
- ; xwerte[i]=xfun(stellen[i]), ywerte[i] = yfun(stellen[i]) für 0<=i<len.
- ; Mit fun(x) := yfun(xfun^-1(x)) also
- ; ywerte[i] = fun(xwerte[i]) für 0<=i<len.
- (do ((i 0 (1+ i))) ((>= i len))
- (do ((j (1+ i) (1+ j))) ((>= j len))
- (setf (aref ywerte j)
- (/ (- (aref ywerte j) (aref ywerte i))
- (- (aref xwerte j) (aref xwerte i))
- ) ) ) )
- ; Nun ist fun(x) =
- ; = ywerte[0]+(x-xwerte[0])*(ywerte[1]+(x-xwerte[1])*(ywerte[2]+...))
- ; für alle x=xwerte[i], 0<=i<len.
- (do ((i (1- len) (1- i))) ((< i 0))
- ; Multipliziere das Polynom
- ; ywerte[i+1]*(x-x0)^0+...+ywerte[len-1]*(x-x0)^(len-i-2) mit
- ; x-xwerte[i] = (x-x0) + (x0-xwerte[i]) und addiere ywerte[i]:
- (let ((c (- x0 (aref xwerte i))))
- (do ((j i (1+ j)))
- ((>= j (1- len)))
- (incf (aref ywerte j) (* c (aref ywerte (1+ j))))
- ) ) )
- ; Nun ist fun(x) = ywerte[0]*(x-x0)^0+ywerte[1]*(x-x0)^1+...
- ; für alle x=xwerte[i], 0<=i<len.
- ywerte
- ) )
-
- (setf (long-float-digits) 665) ; entspricht 200 Dezimalstellen
-
- ;(defparameter pi (* 4 (atan 1L0)))
- (defparameter e (exp 1L0))
-
- (defun myrationalize (a) ; liefert eine rationale Zahl in der Nähe von a.
- ; Kriterium: Kettenbruch-Element >10000
- (when (floatp a) (setq a (rational a)))
- (if (< a 0)
- (- (myrationalize (- a)))
- (let ((p0 1) (q0 0) (p1 (floor a)) (q1 1) next)
- (setq a (- a p1))
- (loop
- (when (zerop a) (return))
- (multiple-value-setq (next a) (floor (/ a)))
- (when (> next 10000) (return))
- (psetq p0 p1 p1 (+ p0 (* p1 next))
- q0 q1 q1 (+ q0 (* q1 next))
- ) )
- (/ p1 q1)
- ) ) )
-
- ; mehr Stellen ergeben größere Rechenzeit, aber auch größere Genauigkeit:
- ; Der relative Fehler in limes ist etwa (1/n)^(Stellenzahl-1) = 1/n^k.
- (defun default-k (&optional (max 100))
- (cond ((>= max 400) 5)
- ((>= max 100) 8)
- ((>= max 20) 10)
- (t (floor max 2))
- ) )
- (defun default-stellen (&optional (max 100) (k (default-k max)))
- ; Liste von max/(1+i/k), i=0..k:
- (do ((i 0 (1+ i))
- (L nil))
- (nil)
- (push (round max (+ 1 (/ i k))) L)
- (when (>= i k) (return L))
- ) )
-
- (defun interpol-ntel (fun &optional (max 100) (k (default-k max))
- (stellen (default-stellen max k)))
- (polynom-interpol #'/ fun stellen)
- )
-
- (defun limes (fun &optional (max 100) (k (default-k max)))
- (aref
- (interpol-ntel
- #'(lambda (n) (coerce (funcall fun n) 'long-float))
- max
- k
- )
- 0
- ) )
-
- ; Bestimmt die Glieder c0, c1, ..., cm einer asymptotischen Entwicklung
- ; fun(n) = c0 + c1*n^-1 + c2*n^-2 + ... + cm*n^-m
- (defun asymptotik (fun m &optional (max 100) (k (default-k max)))
- (let ((c (make-array (1+ m)))
- (Lc (make-array (1+ m)))
- (j 0)
- (hauptnenner 1)) ; Hauptnenner von c[0]..c[j-1]
- (loop
- (setf (aref c j)
- (/ (myrationalize
- (* hauptnenner ; Hauptnenner erleichtert myrationalize
- (limes
- #'(lambda (n)
- (let ((y (funcall fun n)))
- (dotimes (i j) (setq y (* n (- y (aref Lc i)))))
- y
- ) )
- max
- k
- ) ) )
- hauptnenner
- ) )
- (print (aref c j))
- (setq hauptnenner (lcm hauptnenner (denominator (aref c j))))
- (setf (aref Lc j) (coerce (aref c j) 'long-float))
- (incf j)
- (when (> j m) (return))
- )
- c
- ) )
-
-
- ; Aufwand bei max = ca. 100, Stellenzahl k+1 = ca. 6:
- ; Funktion polynom-interpol löst ein LGS mit einer Matrix, die eine
- ; Vandermonde-Matrix zu (2/max, ..., 1/max) ist und daher die Determinante
- ; prod (0<=i<j<=k, ((1+j/k)/max - (1+i/k)/max) )
- ; = 1!2!...k! / (k max)^(k(k+1)/2) hat. (Davon der Logarithmus ->)
- ; Dies verbraucht etwa k^2/2 * (lg e + lg max) Stellen.
- ; Erfahrungsgemäß hat ein so gewonnener limes eine relative Genauigkeit
- ; von 1/max^k, also k * lg max genaue Stellen.
- ; Will man m (= ca. 5) Koeffizienten der asymptotischen Entwicklung aus-
- ; rechnen, so muß man die Werte um m * lg max genauer haben:
- ; Bei (...((Wert - c0) * max - c1) * max ...) gehen m * lg max Stellen
- ; verloren.
- ; Somit muß man etwa m * lg max + k^2/2 * lg (e*max) Stellen vorsehen und
- ; bekommt dann alle Limites mit k * lg max genauen Stellen, und der
- ; Rechenaufwand ist:
- ; m * m mal Limes ziehen
- ; k^2 * k^2 Rechenoperationen
- ; (k^2 lg max)^2 auf Zahlen mit k^2 lg max Stellen
- ; = m * (lg max)^2 * k^6.
- ; Also:
- ; Sofern die Folge leicht berechenbar ist (z.B. durch polynomial lineare
- ; Rekursion), max groß und k klein wählen (z.B. max=400 und k=5 -> 13 Stellen
- ; beim Limes, brauche 85 Stellen und bei m=10 zusätzlich 26 Stellen).
- ; Sofern nur endlich viele Folgenglieder vorliegen, k größer wählen
- ; (was die Rechenzeit steil in die Höhe treibt): z.B. max=50 und k=9 ->
- ; 15 Stellen beim Limes, brauche 96 Stellen und bei m=5 zusätzlich 8 Stellen.
-
- ; Man beachte, daß man einen Koeffizienten c_i EXAKT haben muß, um c_i+1
- ; ausrechnen zu können. Das Ganze ist nämlich extrem empfindlich gegenüber
- ; Fehlern. Um c_i exakt (aus den ersten 14 Stellen des Dezimalbruchs) zu
- ; bestimmen, kann myrationalize dienen (falls c_i rational ist), oder
- ; der LLL-Algorithmus (falls c_i in einem algebraischen Erweiterungskörper
- ; der rationalen Zahlen liegt).
-
- (require 'intmisc) ; defun-N0
-
- #|
- ; Beispiel:
- (require 'kartenf "KARTEN4")
-
- ; Das Originalproblem: (kartenf n)
-
- ; Davon die Fakultätsfaktoren (4n)!/n!^4 entfernen:
- (defun fa (n) (/ (kartenf n) (/ (! (* 4 n)) (expt (! n) 4))))
-
- ; Probiere (limes #'(lambda (n) (/ (fa n) (fa (1- n)))) 100),
- ; sollte etwa 25/64 liefern.
-
- ; Davon die Potenzen (5/8)^2n entfernen:
- (defun fb (n) (/ (fa n) (expt 5/8 (* 2 n))))
-
- ; Probiere (limes #'fb 100), sollte etwa (sqrt 125/216) liefern.
-
- ; Dann in Long-Float umwandeln:
- (defun fc (n) (coerce (fb n) 'long-float))
-
- ; Dann konstanten Faktor (5/6)^(3/2) entfernen:
- (defvar c00 (sqrt (coerce 125/216 'long-float)))
- (defun-N0 f0 (n) (/ (fc n) c00)) ; bis hierher stets nur einmal berechnen
-
- ; Dann die asymptotische Entwicklung bestimmen:
- ; (asymptotik #'f4 2 100)
- ; liefert (1 -35/432 -815/41472) als Anfang der asymptotischen Entwicklung.
- |#
-
- ; oder schrittweise:
- ; c0 = (myrationalize (limes #'f0)) = 1
- (defun f1 (n) (* n (- (f0 n) c0)))
- ; c1 = (myrationalize (limes #'f1))
- (defun f2 (n) (* n (- (f1 n) c1)))
- ; c2 = (myrationalize (limes #'f2))
- (defun f3 (n) (* n (- (f2 n) c2)))
- ; c3 = (myrationalize (limes #'f3))
- (defun f4 (n) (* n (- (f3 n) c3)))
- ; c4 = (myrationalize (limes #'f4))
- (defun f5 (n) (* n (- (f4 n) c4)))
- ; c5 = (myrationalize (limes #'f5))
- (defun f6 (n) (* n (- (f5 n) c5)))
- ; c6 = (myrationalize (limes #'f6))
- (defun f7 (n) (* n (- (f6 n) c6)))
- ; c7 = (myrationalize (limes #'f7))
- (defun f8 (n) (* n (- (f7 n) c7)))
- ; c8 = (myrationalize (limes #'f8))
- (defun f9 (n) (* n (- (f8 n) c8)))
- ; c9 = (myrationalize (limes #'f9))
- (defun f10 (n) (* n (- (f9 n) c9)))
- ; c10 = (myrationalize (limes #'f10))
- (defun f11 (n) (* n (- (f10 n) c10)))
- ; c11 = (myrationalize (limes #'f11))
- (defun f12 (n) (* n (- (f11 n) c11)))
- ; c12 = (myrationalize (limes #'f12))
- (defun f13 (n) (* n (- (f12 n) c12)))
- ; c13 = (myrationalize (limes #'f13))
- (defun f14 (n) (* n (- (f13 n) c13)))
- ; c14 = (myrationalize (limes #'f14))
- (defun f15 (n) (* n (- (f14 n) c14)))
- ; c15 = (myrationalize (limes #'f15))
- (defun f16 (n) (* n (- (f15 n) c15)))
- ; c16 = (myrationalize (limes #'f16))
- (defun f17 (n) (* n (- (f16 n) c16)))
- ; c17 = (myrationalize (limes #'f17))
- (defun f18 (n) (* n (- (f17 n) c17)))
-
- #|; zusammengefaßt:
- (defun f1 (n) (* n (- (f0 n) c0)))
- (defun f2 (n) (* n (- (f1 n) c1)))
- (defun f3 (n) (* n (- (f2 n) c2)))
- (defun f4 (n) (* n (- (f3 n) c3)))
- (defun f5 (n) (* n (- (f4 n) c4)))
- (defun f6 (n) (* n (- (f5 n) c5)))
- (defun f7 (n) (* n (- (f6 n) c6)))
- (defun f8 (n) (* n (- (f7 n) c7)))
- (defun f9 (n) (* n (- (f8 n) c8)))
- (defun f10 (n) (* n (- (f9 n) c9)))
- (defun f11 (n) (* n (- (f10 n) c10)))
- (defun f12 (n) (* n (- (f11 n) c11)))
- (defun f13 (n) (* n (- (f12 n) c12)))
- (defun f14 (n) (* n (- (f13 n) c13)))
- (defun f15 (n) (* n (- (f14 n) c14)))
- (defun f16 (n) (* n (- (f15 n) c15)))
- (defun f17 (n) (* n (- (f16 n) c16)))
- (defun f18 (n) (* n (- (f17 n) c17)))
- |#
-
-